package com.biboheart.adapter.compiler.lexical;

import com.biboheart.adapter.compiler.Lexical;
import com.biboheart.adapter.compiler.enums.BufferType;
import com.biboheart.adapter.compiler.enums.CharType;
import com.biboheart.adapter.compiler.enums.TokenType;
import com.biboheart.adapter.compiler.token.Token;
import com.biboheart.adapter.support.enums.DelimitEnum;
import com.biboheart.adapter.support.enums.InstructEnum;
import com.biboheart.adapter.support.enums.LogicalEnum;
import com.biboheart.adapter.support.enums.OperatorEnum;

import java.util.ArrayList;
import java.util.List;

public class LexicalImpl implements Lexical {
    @Override
    public List<Token> analysis(String content) {
        Scanner scanner = new Scanner(content);
        scanner.start();
        return scanner.getTokenList();
    }

    private static class Scanner {
        private final List<Token> tokenList = new ArrayList<>();
        private final StringBuilder buffer = new StringBuilder(); // 缓冲区
        private int offset = 0; // 当前扫描位置
        private BufferType bufferType = null;
        private final String content;

        public Scanner(String content) {
            this.content = content;
        }

        public List<Token> getTokenList() {
            return tokenList;
        }

        // 扫描代码
        private void start() {
            if (content.isEmpty()) {
                return;
            }
            while (offset < content.length()) {
                pushBuffer(content.charAt(offset));
                offset ++;
            }
            moveBuffer();
        }
        // 状态比较，缓冲器中的单词是否结束
        private CharType getCharType(char ch) {
            CharType charType = null;
            if (ch == 32) { // 空格
                charType = CharType.CHAR_SPACE;
            } else if (ch == '.') {
                charType = CharType.CHAR_DOT;
            } else if ((ch > 64 && ch < 91) || (ch > 96 && ch < 123)) {
                charType = CharType.CHAR_LETTER;
            } else if (ch >= 48 && ch <= 57) {
                charType = CharType.CHAR_NUMBER;
            } else if (ch == 34) {
                charType = CharType.CHAR_DQUOTES;
            } else if (ch == 39) {
                charType = CharType.CHAR_SQUOTES;
            } else if (ch == 96) {
                charType = CharType.CHAR_BACKQUOTE;
            } else if (ch >= 33 && ch <= 47 || ch >= 58 && ch <= 64 || ch >= 91 && ch < 96 || ch >= 123 && ch <= 126) {
                charType = CharType.CHAR_CHARACTER;
            } else {
                charType = CharType.CHAR_OTHER;
            }
            return charType;
        }
        // 将字符加入缓冲器
        private void pushBuffer(char ch) {
            CharType charType = getCharType(ch);
            if (buffer.length() == 0 && null == bufferType) {
                if (CharType.CHAR_SPACE.equals(charType) || CharType.CHAR_OTHER.equals(charType) || CharType.CHAR_DOT.equals(charType)) {
                    // 空格，其他符号，"."不能作为第一个字符或单独字符存在
                    return;
                }
                // 第一个字符约定单词类型
                if (CharType.CHAR_DQUOTES.equals(charType)) {
                    bufferType = BufferType.BUFFER_STRING;
                } else if (CharType.CHAR_SQUOTES.equals(charType)) {
                    bufferType = BufferType.BUFFER_CHARS;
                } else if (CharType.CHAR_LETTER.equals(charType) || CharType.CHAR_UNDERLINE.equals(charType) || CharType.CHAR_BACKQUOTE.equals(charType)) {
                    bufferType = BufferType.BUFFER_COMMAND;
                    buffer.append(ch);
                } else if (CharType.CHAR_NUMBER.equals(charType)) {
                    bufferType = BufferType.BUFFER_NUMBER;
                    buffer.append(ch);
                } else {
                    bufferType = BufferType.BUFFER_CHARACTER;
                    buffer.append(ch);
                }
                return;
            }
            if (BufferType.BUFFER_COMMAND.equals(bufferType) && (CharType.CHAR_LETTER.equals(charType)
                    || CharType.CHAR_UNDERLINE.equals(charType)
                    || CharType.CHAR_NUMBER.equals(charType)
                    || CharType.CHAR_DOT.equals(charType)
                    || CharType.CHAR_BACKQUOTE.equals(charType)
            )) {
                buffer.append(ch);
                if (CharType.CHAR_BACKQUOTE.equals(charType)) {
                    moveBuffer();
                }
                return;
            }
            if (BufferType.BUFFER_CHARS.equals(bufferType) && !CharType.CHAR_SQUOTES.equals(charType)) {
                buffer.append(ch);
                return;
            }
            if (!BufferType.BUFFER_CHARS.equals(bufferType) && CharType.CHAR_SQUOTES.equals(charType)) {
                moveBuffer();
                bufferType = BufferType.BUFFER_CHARS;
                return;
            }
            if (BufferType.BUFFER_STRING.equals(bufferType) && !CharType.CHAR_DQUOTES.equals(charType)) {
                buffer.append(ch);
                return;
            }
            if (!BufferType.BUFFER_STRING.equals(bufferType) && CharType.CHAR_DQUOTES.equals(charType)) {
                moveBuffer();
                bufferType = BufferType.BUFFER_STRING;
                return;
            }
            if (BufferType.BUFFER_NUMBER.equals(bufferType) && (CharType.CHAR_DOT.equals(charType) && !buffer.toString().contains(".") || CharType.CHAR_NUMBER.equals(charType))) {
                buffer.append(ch);
                return;
            }
            if (BufferType.BUFFER_CHARACTER.equals(bufferType) && CharType.CHAR_CHARACTER.equals(charType)) {
                if (preScan()) {
                    buffer.append(ch);
                    return;
                }
            }
            moveBuffer();
            if (CharType.CHAR_SPACE.equals(charType) || DelimitEnum.DELIMIT_SEM.code().equals(String.valueOf(ch)) || CharType.CHAR_SQUOTES.equals(charType) || CharType.CHAR_DQUOTES.equals(charType)) {
                return;
            }
            // 把字符放入下一轮
            pushBuffer(ch);
        }
        // 当单词结束时，将缓冲器中的值移到token流
        private void moveBuffer() {
            if (null == bufferType) {
                return;
            }
            TokenType tokenType = null;
            String code = null;
            if (BufferType.BUFFER_NUMBER.equals(bufferType) || BufferType.BUFFER_STRING.equals(bufferType) || BufferType.BUFFER_CHARS.equals(bufferType)) {
                tokenType = TokenType.TOKEN_CONSTANT;
                code = "constant";
            } else if (BufferType.BUFFER_COMMAND.equals(bufferType)) {
                tokenType = InstructEnum.contains(buffer.toString()) ? TokenType.TOKEN_KEYWORD : TokenType.TOKEN_VARIABLE;
                if (CharType.CHAR_BACKQUOTE.equals(getCharType(buffer.charAt(0)))) {
                    // 去掉反单引号
                    buffer.deleteCharAt(buffer.length() - 1).deleteCharAt(0);
                }
                code = buffer.toString();
            } else {
                if (DelimitEnum.contains(buffer.toString())) {
                    tokenType = TokenType.TOKEN_DELIMITERS;
                    code = buffer.toString();
                } else if (LogicalEnum.contains(buffer.toString())) {
                    tokenType = TokenType.TOKEN_LOGICAL;
                    code = buffer.toString();
                } else if (OperatorEnum.contains(buffer.toString())) {
                    tokenType = TokenType.TOKEN_OPERATOR;
                    code = buffer.toString();
                }
            }
            Object value;
            if ("null".contentEquals(buffer) && TokenType.TOKEN_VARIABLE.equals(tokenType)) {
                tokenType = TokenType.TOKEN_CONSTANT;
                code = "constant";
                value = null;
            } else if (BufferType.BUFFER_NUMBER.equals(bufferType)) {
                String bufferStr = buffer.toString();
                if (bufferStr.contains(".")) {
                    value = Double.valueOf(bufferStr);
                } else if (bufferStr.length() > 10) {
                    value = Long.parseLong(bufferStr);
                } else {
                    value = Integer.parseInt(bufferStr);
                }
            } else {
                value = buffer.toString();
            }
            bufferType = null;
            if (null == tokenType) {
                buffer.setLength(0);
                return;
            }
            Token token = new Token(tokenList.size(), 0, tokenType, code, value, buffer.toString());
            tokenList.add(token);
            buffer.setLength(0);
        }
        /**
         * 预扫，预判上下文关联性
         * @return 如果无关联，返回false
         */
        private boolean preScan() {
            if (buffer.length() == 0 && null == bufferType) {
                return true;
            }
            StringBuilder sb = new StringBuilder(buffer);
            int i = 0;
            for (; i < content.length() - offset; i++) {
                char ch = content.charAt(offset + i);
                CharType charType = getCharType(ch);
                if (BufferType.BUFFER_CHARACTER.equals(bufferType) && !CharType.CHAR_CHARACTER.equals(charType)) {
                    break;
                }
                sb.append(ch);
            }
            if (0 == i) {
                return false;
            }
            while (i > 0) {
                if (DelimitEnum.contains(sb.toString())) {
                    break;
                } else if (LogicalEnum.contains(sb.toString())) {
                    break;
                } else if (OperatorEnum.contains(sb.toString())) {
                    break;
                }
                sb.deleteCharAt(sb.length() - 1);
                i --;
            }
            return i > 0;
        }
    }
}
